# -*- coding: utf-8 -*-
"""
Created on Thu Aug 10 08:36:09 2023

@author: 李小斌
"""

import os
import math
import numpy as np
from sklearn.model_selection import KFold
#from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso
from sklearn.ensemble import BaggingRegressor
from sklearn.tree import ExtraTreeRegressor
from sklearn import neighbors
from sklearn import svm
from sklearn import tree
from sklearn import ensemble
from sklearn.metrics import mean_squared_error
import csv
#from gplearn import genetic
#from gplearn.genetic import SymbolicRegressor
#from datetime import datetime

dimension=400
    
def ontime(modelname,nfolds):
    csv_reader=csv.reader(open('all'+str(dimension)+'.csv'))
    
    L1=[]
    y=[]                        #期末成绩,final
    #x=[]                       #平时所有数据
    xtest=[]                      #平时测验
    xhomework=[]                  #平时2次作业
    xexperiment=[]              #平时的16次实验
    xevaluation=[]              #教学评价
    
    n=0
    for row in csv_reader:
        if n==0:
            n=n+1
            continue
        n=n+1
        y.append(row[1])                 #final
        xtest.append(row[2:4])           #2次平时测验
        xhomework.append(row[4:6])      #2次作业
        xexperiment.append(row[6:22])   #16次实验
        xevaluation.append(row[22:22+3*dimension])  #3次评价的语义嵌入
        

    
    #将所有数据转化为float类型数据
    ya=np.array(y,dtype=float)
    ya=ya/100
    xtesta=np.array(xtest,dtype=float)
    xtesta=xtesta/100    
    xhomeworka=np.array(xhomework,dtype=float) 
    xhomeworka=xhomeworka/100
    xexperimenta=np.array(xexperiment,dtype=float) 
    xexperimenta=xexperimenta/100
    xevaluationa=np.array(xevaluation,dtype=float)                       

    
    #nfolds=5
    kf = KFold(n_splits=nfolds,shuffle=False)  # 初始化KFold
    if modelname=='LR':
        model = LinearRegression()
    elif modelname=='Ridge':
        model = Ridge(alpha=.5)
    elif modelname=='Lasso':
        model=Lasso(alpha=.5)
    elif modelname=='SVR':
        model=svm.SVR()
    elif modelname=='DT':
        model=tree.DecisionTreeRegressor()
    elif modelname=='KNN':
        model=neighbors.KNeighborsRegressor()
    elif modelname=='RandomForest':
        model=ensemble.RandomForestRegressor(n_estimators=20)
    elif modelname=='Adaboost':
        model=ensemble.AdaBoostRegressor(n_estimators=20)
    elif modelname=='GBRT':
        model=ensemble.GradientBoostingRegressor(n_estimators=20)
    elif modelname=='Bagging':
        model=BaggingRegressor()
    elif modelname=='ExtraTree':
        model=ExtraTreeRegressor()
    #model用于预测测验，model1用于预测作业,model2用于预测实验，model3用于预测评价
    #model4用于合并预测
    model1=model
    model2=model
    model3=model
    model4=model  
    
    for train_index , test_index in kf.split(ya):  # 调用split方法切分数据
        
        #第1层训练
        model.fit(xtesta[train_index],ya[train_index])
        yp0=model.predict(xtesta[train_index])
        ypt0=model.predict(xtesta[test_index])
        
        model1.fit(xhomeworka[train_index],ya[train_index])
        yp1=model1.predict(xhomeworka[train_index])
        ypt1=model1.predict(xhomeworka[test_index])
        
        model2.fit(xexperimenta[train_index],ya[train_index])
        yp2=model2.predict(xexperimenta[train_index])
        ypt2=model2.predict(xexperimenta[test_index])
        
        model3.fit(xevaluationa[train_index],ya[train_index])
        yp3=model3.predict(xevaluationa[train_index]) 
        ypt3=model3.predict(xevaluationa[test_index])
        
        #第2层训练
        yptrain=np.vstack((yp0,yp1,yp2,yp3))
        yp2nd=np.transpose(yptrain)
        model4.fit(yp2nd,ya[train_index])
        
        yptest=np.vstack((ypt0,ypt1,ypt2,ypt3))
        ypt2nd=np.transpose(yptest)
        yppt2nd=model4.predict(ypt2nd)
       
        #计算最终rmse               
        rmse=math.sqrt(mean_squared_error(ya[test_index],yppt2nd))
        L1.append(rmse)
        
  
    return [L1]

def evaluate(modelname,ntimes,nfolds):
    file=open(modelname+'.csv','w',newline='')       
    f_csv=csv.writer(file)
    header=['rmse']
    f_csv.writerow(header)
    times=0
    while times<ntimes:
        L=ontime(modelname,nfolds)
        Lw=[]           #用于获取L1-L8中相同位置的rmse，构造成一个list存入csv    
        for pos in range(0,nfolds):
            for Litem in L:
                Lw.append(Litem[pos])
            f_csv.writerow(Lw)
            Lw=[]
        times+=1
    file.close()

def getRmse(modelname):
    filepath=modelname+'.csv'
    file=open(filepath)
    csv_reader=csv.reader(file)    
    x=[]
    n=0
    for row in csv_reader:
        if n==0:
            n=n+1
            continue
        n=n+1
        x.append(row[0])                    
    #将所有数据转化为float类型数据
    file.close()
    os.remove(filepath)
    xa=np.array(x,dtype=float)
    return np.mean(xa)
    
def main():
    #模型名称，LR,Ridge,Lasso,SVR,DT,KNN,RandomForest,Adaboost,GBRT,Bagging,ExtraTree
    ntimes=20#运行总次数
    nfolds=5#fold的次数
    modelnames=['LR','Ridge','Lasso','SVR','DT','KNN','RandomForest',
                'Adaboost','GBRT','Bagging','ExtraTree']
    file=open('decision_fusion'+str(dimension)+'.csv','w',newline='')       
    f_csv=csv.writer(file)
    for modelname in modelnames:
        evaluate(modelname,ntimes,nfolds)
        v=getRmse(modelname)
        print(modelname,":",v)
        f_csv.writerow([modelname,v])
    file.close()
if __name__=="__main__":
    main()